#pragma once
#include <iostream>
#include "Connection.hpp"
#include "Log.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <functional>

class HandlerConnection
{
public:
    HandlerConnection(func_t func)
        : _func(func)
    {
    }
    // 处理读方法
    void HandlerRecv(Connection *conn)
    {
        errno = 0;
        LOG(DEBUG, "HandlerRecv fd:%d\n", conn->Sockfd());
        // 这里是非阻塞ET模式，只会通知一次，所以需要一直循环获取数据，直到获取完数据即可
        while (true)
        {
            char buffer[1024]; // 每次拿取1024
            ssize_t n = recv(conn->Sockfd(), buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = '\0';
                // 读取成功-将此次读取的小块数据放入此fd的输入缓冲区中
                conn->AppendInBuffer(buffer);
            }
            else
            {
                // 读取出错---所有的错误都会转化为读写错误
                // 表示本次读取没有读到信息，这时，表示内核中的数据已经被读取完了，break即可
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    // 表示读取的时候被信号中断了，继续读取即可
                    continue;
                }
                else
                {
                    // 表示读取错误---所有的错误都会转化为读写错误
                    // 直接抛给异常处理函数，让它去处理
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        // 此时，内核中的数据已被全部读取到sock inbuffer中
        _func(conn);
    }
    // 处理写方法
    void HandlerSend(Connection *conn)
    {
        errno = 0;
        // 循环的将发送缓冲区中的数据迁移到内核发送缓冲区中
        while (true)
        {
            ssize_t n = send(conn->Sockfd(), conn->Outbuffer().c_str(), conn->Outbuffer().size(), 0);
            if (n > 0)
            {
                // 发送了n个数据
                // 将已经迁移到内核发送缓冲区的数据从用户发送缓冲区中移走
                conn->OutbufferRemove(n);
                // 如果此时用户发送缓冲区中没有数据了，也就不用发送了，发送就结束了
                if (conn->OutbufferEmpty() == true)
                {
                    break; // 用户发送缓冲区中没有数据了
                }
            }
            else if (n == 0)
            {
                // 发送了0个数据
                // 表示此次发送已经将用户缓冲区中的数据全部迁移到内核发送缓冲区中了
                // 返回即可
                break; // 用户发送缓冲区中没有数据了
            }
            else
            {
                // 发送失败了
                // 内核发送缓冲区被写满了
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break; // 内核发送缓冲区被写满了
                }
                // 发送过程被信号中断了
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    // 表示发送失败了
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        // 此处，内核发送缓冲区已经被写满了
        // 如果此时用户发送缓冲区中还有数据的话，就需要让epoll写入剩下的数据到内核缓冲区中了
        if (conn->OutbufferEmpty() == false) // 让epoll帮忙在底层进行等待
        {
            // 开启对读写事件的关心
            conn->_R->EnableReadWrite(conn->Sockfd(), true, true);
        }
        else
        {
            // 用户发送缓冲区中没有数据了
            // 关闭对写事件的关心
            conn->_R->EnableReadWrite(conn->Sockfd(), true, false);
        }
    }
    // 处理异常方法
    void HandlerExcept(Connection *conn)
    {
        errno = 0;
        // 这里设置errno为0是因为，此Reactor是单进程且会调用很多函数，且还要管理很多的fd
        // 所以errno错误码可能是因为调用上次的fd的某函数发生错误，而使errno发生改变，
        // 此次fd调用函数时，就可能会因为上次的fd的错误而影响到这次的fd
        // 为了不让上次的errno干扰到这次的fd的处理方法，就将这个errno每次都设置为0
        LOG(DEBUG, "客户端退出！ fd:%d\n", conn->Sockfd());
        // 顺序！！！
        conn->_R->RemoveConnection(conn->Sockfd());
    }

private:
    func_t _func;
};